﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.AspNet;
using Microsoft.Web.WebPages.OAuth;
using WebMatrix.WebData;
using PlanificadorDeEventos.Filters;
using PlanificadorDeEventos.Models;
using PlanificadorDeEventos.Repositorios;
using PlanificadorDeEventos.Comun;
using MvcFilters.Filters;
using PlanificadorDeEventos.Interfaces;

namespace PlanificadorDeEventos.Controllers
{
    [Authorize]
    [InitializeSimpleMembership]
    [HandleError]
    public class AccountController : Controller
    {
       
        #region Miembros privados
        IRepositorioGuests repoGuest = null;
        IRepositorioEventos repoEventos = null;
        IRepositorioEventoUsuarioOrganizados repoEventosOrganizados = null;
        IRepositorioEventoUsuarioRegistrados repoEventosRegistrados = null;
        #endregion

        #region Constructor
        public AccountController(IRepositorioEventos RepositorioEventos, IRepositorioEventoUsuarioOrganizados RepositorioEventoUsuarioOrganizados, IRepositorioEventoUsuarioRegistrados RepositorioEventoUsuarioRegistrados, IRepositorioGuests RepositorioGuests)
        {
            repoEventos = RepositorioEventos;
            repoEventosOrganizados = RepositorioEventoUsuarioOrganizados;
            repoEventosRegistrados = RepositorioEventoUsuarioRegistrados;
            repoGuest = RepositorioGuests;
        }

        #endregion

        #region Métodos públicos
        [AllowAnonymous]
        public ActionResult Login(string returnUrl)
        {
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }

        //
        // POST: /Account/Login

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        [TraceFilter]
        [LogErrors]
        public ActionResult Login(LoginModel model, string returnUrl)
        {
            if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
            {
                if (Roles.GetRolesForUser(model.UserName).Contains("Admin"))
                    ViewBag.isAdmin = true;
                else
                    ViewBag.isAdmin = false;
                return RedirectToLocal(returnUrl);
            }

            ModelState.AddModelError("", "El nombre de usuario o password es incorrecto.");
            return View(model);

        }

        //
        // POST: /Account/LogOff

        [HttpPost]
        [ValidateAntiForgeryToken]
        [TraceFilter]
        [LogErrors]
        public ActionResult LogOff()
        {
            WebSecurity.Logout();
            return RedirectToAction("Index", "Home");
        }

        //
        // GET: /Account/Register

        [AllowAnonymous]
        [TraceFilter]
        [LogErrors]
        public ActionResult Register()
        {
            return View();
        }

        //
        // POST: /Account/Register

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        [TraceFilter]
        [LogErrors]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    ViewBag.msg = "";
                    string result = WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { email = model.Email });
                    if (result.Equals("success"))
                    {
                        WebSecurity.Login(model.UserName, model.Password);
                        return RedirectToAction("Index", "Home");
                    }
                    else
                        ViewBag.msg = "El Nombre de usuario ya existe!";
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        //
        // GET: /Account/Manage

        public ActionResult Manage(ManageMessageId? message, int? idUser)
        {
            LocalPasswordModel localPassModel = new LocalPasswordModel();
            if (idUser != null)
            {
                User user = (User)repoGuest.GetByID(idUser);
                localPassModel.Nombre = user.Nombre;
                localPassModel.Email = user.Email;
                ViewBag.isAdmin = true;
            }
            else
            {
                Guest guest = repoGuest.ObtenerPorNombre(User.Identity.Name);
                if (guest != null)
                {
                    ViewBag.isAdmin = false;
                    localPassModel.Nombre = guest.Nombre;
                    localPassModel.Email = guest.Email;
                }

            }

            ViewBag.isAdmin = ViewBag.isAdmin || Roles.GetRolesForUser(User.Identity.Name).Contains("Admin");

            ViewBag.StatusMessage = message == ManageMessageId.ChangePasswordSuccess ? "El usuario ha sido actualizado" : "";
            ViewBag.HasLocalPassword = WebSecurity.HasUserId;
            ViewBag.ReturnUrl = Url.Action("Manage");
            return View(localPassModel);
        }

        //
        // POST: /Account/Manage

        [HttpPost]
        [ValidateAntiForgeryToken]
        [TraceFilter]
        [LogErrors]
        public ActionResult Manage(LocalPasswordModel model)
        {
            Guest user = null;
            bool hasLocalAccount = WebSecurity.HasUserId;
            ViewBag.HasLocalPassword = hasLocalAccount;
            ViewBag.ReturnUrl = Url.Action("Manage");
            if (hasLocalAccount)
            {
                if (ModelState.IsValid)
                {
                    // ChangePassword will throw an exception rather than return false in certain failure scenarios.
                    bool changePasswordSucceeded;
                    try
                    {
                        changePasswordSucceeded = WebSecurity.ChangePassword(model.Nombre, model.OldPassword, model.NewPassword);
                        user = repoGuest.ObtenerPorNombre(model.Nombre);
                        user.Email = model.Email;
                        repoGuest.ActualizarUsuario(user);
                        ViewBag.UserName = model.Nombre;
                    }
                    catch (Exception)
                    {
                        changePasswordSucceeded = false;
                    }

                    if (changePasswordSucceeded)
                    {
                        return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess, idUser = user.ID });
                    }
                    else
                    {
                        ModelState.AddModelError("", "El password actual es incorrecto o el nuevo password es inválido.");
                    }
                }
            }
            // If we got this far, something failed, redisplay form
            return View(model);
        }


        //
        // GET: /Account/ExternalLoginFailure
        [TraceFilter]
        [LogErrors]
        public ActionResult EliminarCuenta()
        {
            ViewBag.nombreAccion = "¿Desea eliminar su cuenta?";
            ViewBag.accionConfirmar = "EliminarCuentaConfirmed";
            ViewBag.idAEliminar = "";
            return PartialView("../Shared/popUpConfirmacion");
        }

        [TraceFilter]
        [LogErrors]
        public ActionResult EliminarCuentaConfirmed()
        {
            User user = (User)repoGuest.ObtenerPorNombre(System.Web.HttpContext.Current.User.Identity.Name);
            if (user == null)
                return View("../Shared/Error");
            IEnumerable<EventoUsuarioRegistrado> eur = repoEventosRegistrados.ObtenerPorIdUser(user.ID);
            repoEventosRegistrados.DeleteAll(eur.ToList());
            IEnumerable<EventoUsuarioOrganizado> euo = repoEventosOrganizados.ObtenerPorIdUser(user.ID);

            foreach (var eventoOrganizado in euo.ToList())
            {
                if (repoEventosOrganizados.CantidadDeOrganizadoresPorIdEvento(eventoOrganizado.EventoID).Equals(1)) //el usuario a eliminar es el unico organizador del evento
                {
                    List<EventoUsuarioRegistrado> allRegistraciones = repoEventosRegistrados.ObtenerPorIdEvento(eventoOrganizado.EventoID).ToList();
                    repoEventosRegistrados.DeleteAll(allRegistraciones);
                    repoEventos.Delete(eventoOrganizado.EventoID);
                }
            }
            repoEventosOrganizados.DeleteAll(euo.ToList());
            repoGuest.Delete(user.ID);
            WebSecurity.Logout();
            return PartialView("../Evento/Close");
        }

        #endregion

        #region Helpers
        private ActionResult RedirectToLocal(string returnUrl)
        {
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }

        public enum ManageMessageId
        {
            ChangePasswordSuccess,
            SetPasswordSuccess,
            RemoveLoginSuccess,
        }

        internal class ExternalLoginResult : ActionResult
        {
            public ExternalLoginResult(string provider, string returnUrl)
            {
                Provider = provider;
                ReturnUrl = returnUrl;
            }

            public string Provider { get; private set; }
            public string ReturnUrl { get; private set; }

            public override void ExecuteResult(ControllerContext context)
            {
                OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);
            }
        }

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "El nombre de usuario ya existe. Introduzca un nombre de usuario diferente.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "Ya existe un usuario asociado a ese e-mail. Introduzca otra dirección de e-mail.";

                case MembershipCreateStatus.InvalidPassword:
                    return "El password es inválido. Introduzca un password válido.";

                case MembershipCreateStatus.InvalidEmail:
                    return "La dirección de e-mail es inválida. Revise la dirección de e-mail.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "La respuesta para la recuperación de contraseña es invalida. Revise la respuesta y vuelva a intentarlo.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "La pregunta para la recuperación de contraseña es invalida. Revise la pregunta y vuelva a intentarlo.";

                case MembershipCreateStatus.InvalidUserName:
                    return "El nombre de usuario es inválido. Revise el nombre de usuario.";

                case MembershipCreateStatus.ProviderError:
                    return "El aunteticador retorno un error, verifique sus datos y vuelva a intentarlo. Si el error persiste contacte a su administrador.";

                case MembershipCreateStatus.UserRejected:
                    return "La creación de usuario ha sido cancelada, verifique sus datos y vuelva a intentarlo. Si el error persiste contacte a su administrador.";

                default:
                    return "Error desconocido, verifique sus datos y vuelva a intentarlo. Si el error persiste contacte a su administrador.";
            }
        }

        #endregion
    }
}
